/*
 * StringGenerator
 * 
 * Version 
 *
 * 23/10/2013
 * 
 * Licencia
 */

/*
 String expresion = "({{[0-9],2},*}{{0|8},5})";
 StringGenerator s = new StringGenerator(expresion);
 s.interpreta();
 //s.getHilera();
 */
package proyecto2.logica;

import java.util.ArrayList;

public class StringGenerator {

    private static final int REGLA_RANGO = 1;
    private static final int REGLA_ASTERISCO = 2;
    private static final int REGLA_CANTIDAD = 3;
    private static final int REGLA_OPCIONAL = 4;

    private ArrayList<String> caracteres;
    private String exp;
    private int cantidadParentesis;
    private int cantidadParentesisQ;
    private int cantidadIntervalo;
    ArrayList<String> reglas;
    private String hilera;

    public StringGenerator(String exp) {
        this.exp = exp;
        reglas = new ArrayList<>();
        this.hilera = "";
        caracteres = new ArrayList<>();
        caracteres.add("[");
        caracteres.add("]");
        caracteres.add("(");
        caracteres.add(")");
        caracteres.add("{");
        caracteres.add("}");
        caracteres.add("*");
        caracteres.add("|");
        caracteres.add("?");
    }

    public String getHilera() {
        String hilera = "";
        ArrayList<String> pendientes = this.reglas;

        String st;
        int multiplicidad;
        for (int i = 0; i < reglas.size(); i++) {
            st = reglas.get(i);
            int tipo = tipoRegla(st);
            if (!esReglaCompuesta(st)) {
                switch (tipo) {
                    case REGLA_CANTIDAD:
                        break;
                    case REGLA_RANGO:
                        break;
                    default:
                        break;
                }
            }
            /*switch (tipo) {
             case REGLA_RANGO:
             System.out.println(st + "----> Regla Rango");
             break;
             case REGLA_ASTERISCO:
             System.out.println(st + "----> Regla Asterisco");
             break;
             case REGLA_CANTIDAD:
             System.out.println(st + "----> Regla Cantidad");
             break;
             }*/
        }
        return "";
        /*while (true) {
         if (reglas.size() > 0) {
         }

         return hilera;
         }*/
    }

    public String getHilera(int minLength, int maxLength) {
        return null;
    }

    public int tipoRegla(String regla) {
        char prim = regla.charAt(0);
        for (int i = 0; i < regla.length(); i++) {
            if (regla.charAt(i) == '[') {
                return REGLA_RANGO;
            }

        }
        switch (prim) {
            case '[':
                return REGLA_RANGO;
            case '{':
                char ult = regla.charAt(regla.length() - 1);
                switch (ult) {
                    case '*':
                        return REGLA_ASTERISCO;
                    default:
                        return REGLA_CANTIDAD;
                }
            default:
                return -1;
        }
    }

    public ArrayList<String> getRango(String regla) {
        ArrayList<String> rango = new ArrayList<>();
        StringBuilder aux = new StringBuilder(regla);
        int inid1d = aux.indexOf("[");
        int fin1d = aux.indexOf("-");
        int fin2d = aux.indexOf("]");
        
        String primerDigito = aux.substring(inid1d + 1, fin1d);
        String segundoDigito = aux.substring(fin1d + 1, fin2d);
        rango.add(primerDigito);
        rango.add(segundoDigito);
        return rango;
    }

    public String reglaInterior(String regla) {
        String r1 = regla;
        StringBuilder aux = new StringBuilder(regla);
        int posIn = aux.indexOf("{");
        aux.deleteCharAt(posIn);
        posIn = aux.indexOf("{");
        int posFn = aux.lastIndexOf("}");
        aux.deleteCharAt(posFn);
        posFn = aux.lastIndexOf("}");
        String hij = aux.substring(posIn, posFn + 1);
        return hij;

    }

    public String getCantidad(String regla) {
        String cantidad = "";
        StringBuilder aux = new StringBuilder(regla);
        int iniposRango = aux.lastIndexOf("{");
        int finposRango = aux.indexOf("}");
        cantidad = aux.substring(iniposRango + 1, finposRango);
        return cantidad;

    }

    public int cantidadEspeciales(String regla) {
        int cc = 0;
        for (int i = 0; i < regla.length(); i++) {
            if (esCaracterReservado(regla.charAt(i))) {
                cc++;
            }
        }
        return cc;

    }

    public void extraeReglas(String exp, ArrayList<String> reglas) {
        while (exp.length() > 0 && exp.length() != 2) {
            exp = obtenerRegla(exp, reglas);
        }

    }

    public void generar() {
        for (String regla : reglas) {
            ejecuta(regla);
        }

    }

    public void ejecuta(String regla) {
        if (!esReglaCompuesta(regla)) {
            int cantidad = getMultiplicidad(regla);
            int tipo = tipoRegla(regla);
            switch (tipo) {
                case REGLA_RANGO:
                    ArrayList<String> rango = getRango(regla);
                    for (int i = 0; i < cantidad; i++) {
                        this.hilera += reglaRango(rango.get(0) + "-" + rango.get(1));
                    }
                    break;
                case REGLA_CANTIDAD:
                    String c = getCantidad(regla);
                    for (int i = 0; i < cantidad; i++) {
                        this.hilera += c;
                    }
                    break;
                default:
                    

            }
        } else {
            int cantidad = getMultiplicidad(regla);
            
            String hi = reglaInterior(regla);
            for (int i = 0; i < cantidad; i++) {
                ejecuta(hi);
            }

        }
    }

    public String crea(String regla) {
        this.hilera += "";
        
        return "";
    }

    public String obtenerReglaHija(String regla) {
        String hija = "";
        if (!esReglaCompuesta(regla)) {
            return regla;
        } else {
            int cc = 0;
            for (int i = 0; i < regla.length(); i++) {
                if (esCaracterReservado(regla.charAt(i))) {
                    cc++;
                    if (cc == 2) {
                        int cierre = obtenerPosicionCierre(i, regla.charAt(i), regla);
                        hija = regla.substring(i - 1, cierre + 1);
                        return hija;
                    }
                }
            }
        }
        return hija;
    }

    public int getMultiplicidad(String regla) {
        int m = 0, inde;
        StringBuilder aux = new StringBuilder(regla);
        inde = aux.lastIndexOf(",");
        if (inde == -1) {
            return inde;
        }
        String multi = aux.substring(inde + 1, aux.length() - 1);
        if (multi.equals("*")) {
            double num = Math.random() * (10 - 3);
            Integer numero = (int) num;
            numero += 3;
            return numero;
        } else {
            return Integer.valueOf(multi);
        }
    }

    
    public String interpreta() {
        this.hilera = "";
        ArrayList<String> usados = new ArrayList<>();
        exp = verificarO(exp);
        extraeReglas(this.exp, this.reglas);
        
        generar();
        return this.hilera;
    }

    public String obtenerRegla(String exp, ArrayList<String> rls) {

        
        StringBuilder cons = new StringBuilder(exp);
        for (int i = 0; i < exp.length(); i++) {
            if (esCaracterReservado(exp.charAt(i))) {
                int f = obtenerPosicionCierre(i, exp.charAt(i), exp);
                if (f > 0) {
                    if (exp.charAt(i) != '(') {
                        rls.add(exp.substring(i, f + 1));
                        return cons.replace(i, f + 1, "").toString();
                    }
                }
            }

        }
        String regla = "";
        return regla;

    }

    public boolean esReglaCompuesta(String regla) {
        StringBuilder aux = new StringBuilder(regla);
        int in1 = aux.indexOf(",");
        int in2 = aux.lastIndexOf(",");
        return in1 == in2 ? false : true;

    }

    public String verificarO(String exp) {
        
        ArrayList<Integer> posiciones;
        StringBuilder expres = new StringBuilder(exp);
        int ini1, ini2, f1, f2, posO;
        try {
            while (true) {
                posiciones = posOcurrencias('|', exp);
                if (posiciones.size() > 0) {
                    posO = posiciones.get(0);
                    ini2 = posO + 1;
                    f1 = posO - 1;
                    if (!esCaracterReservado(exp.charAt(f1))) {
                        ini1 = f1;

                    } else {
                        ini1 = obtenerPosicionAbre(f1, exp.charAt(f1), exp);
                    }
                    if (!esCaracterReservado(exp.charAt(ini2))) {
                        f2 = ini2;
                    } else {
                        f2 = obtenerPosicionCierre(ini2, exp.charAt(ini2), exp);
                    }
                    double rand = Math.random() * 1;
                    long x = Math.round(rand);
                    if (x == 1) {
                        if (f2 == ini2) {
                            expres.replace(f2 - 1, f2 + 1, "");
                            exp = expres.toString();
                        } else {
                            expres.replace(ini2 - 1, f2 + 1, "");
                            exp = expres.toString();
                        }
                    } else {
                        if (ini1 == f1) {
                            expres.replace(f1, f1 + 2, "");
                            exp = expres.toString();
                        } else {
                            expres.replace(ini1, f1 + 2, "");
                            exp = expres.toString();

                        }
                    }
                } else {
                    return exp;
                }
            }
        } catch (Exception ex) {
            
            return verificarO(exp);

        }

    }

    public ArrayList<Integer> posOcurrencias(char caracter, String exp) {
        ArrayList<Integer> posiciones = new ArrayList<>();
        for (int i = 0; i < exp.length(); i++) {
            if (exp.charAt(i) == caracter) {
                posiciones.add(i);
            }
        }
        return posiciones;
    }

    public boolean esta(ArrayList<String> lista, char caracter) {
        for (String s : lista) {
            if (s.equals(String.valueOf(caracter))) {
                return true;
            }
        }
        return false;
    }

    public boolean esta(String string, char caracter) {
        for (int i = 0; i < string.length(); i++) {
            if (string.charAt(i) == caracter) {
                return true;
            }
        }
        return false;
    }

    public int ocurrencias(String string, char caracter) {
        int oc = 0;
        for (int i = 0; i < string.length(); i++) {
            if (string.charAt(i) == caracter) {
                oc++;
            }
        }
        return oc;
    }

    public String reglaRango(String regla) {
        try {
            String[] numeros = regla.split("-");
            Integer min = Integer.valueOf(numeros[0]);
            Integer max = Integer.valueOf(numeros[1]);
            double re = Math.random() * (max - min);
            Integer numero = (int) re;
            numero += min;
            return String.valueOf(numero);
        } catch (NumberFormatException ex) {
            String nueva = regla.toUpperCase();
            Integer min = Integer.valueOf(nueva.charAt(0));
            Integer max = Integer.valueOf(nueva.charAt(2));
            int resultado = (int) (Math.random() * (max - min));
            resultado += min;
            char letra = (char) resultado;
            return String.valueOf(letra);
        }
    }

    public String getCaracter(int tipo) {
        if (tipo == 1) {
            double a = Math.random() * (9 - 0);
            return String.valueOf((int) a);
        } else {
            double a = Math.random() * (90 - 65);
            a += 65;
            char resultado = (char) a;
            return String.valueOf(resultado);
        }
    }

    public boolean esCaracterReservado(char caracter) {
        for (String car : caracteres) {
            if (car.equals(String.valueOf(caracter))) {
                return true;
            }
        }
        return false;
    }

    public int obtenerPosicionCierre(int posActual, char caracter, String exp) {
        char cierre = getCierre(caracter);
        int padre = 0;
        for (int i = posActual + 1; i < exp.length(); i++) {
            if (exp.charAt(i) == caracter) {
                padre++;
            }
            if (exp.charAt(i) == cierre) {
                if (padre == 0) {
                    return i;
                } else {
                    padre--;
                }
            }
        }
        return -1;
    }

    public int obtenerPosicionAbre(int posActual, char caracter, String exp) {
        char cierre = getAbre(caracter);
        int padre = 0;
        for (int i = posActual; i > 0; i--) {
            if (exp.charAt(i) == caracter) {
                padre++;
            }
            if (exp.charAt(i) == cierre) {
                if (padre == 1) {
                    return i;
                } else {
                    padre--;
                }
            }
        }
        return posActual;
    }

    public char getCierre(char caracter) {
        switch (caracter) {
            case '{':
                return '}';
            case '(':
                return ')';
            case '[':
                return ']';
        }
        return ' ';
    }

    public char getAbre(char caracter) {
        switch (caracter) {
            case '}':
                return '{';
            case ')':
                return '(';
            case ']':
                return '[';
        }
        return ' ';
    }

    public boolean abreRegla(char caracter) {
        switch (caracter) {
            case '{':
                return true;
            case '(':
                return true;
            case '[':
                return true;
            case '|':
                return true;
        }
        return false;
    }

    public int busca(char caracter) {
        int cc = 0;
        char cierre = getCierre(caracter);
        for (int i = 0; i < exp.length(); i++) {
            if (exp.charAt(i) == caracter || exp.charAt(i) == cierre) {
                cc++;
            }
        }
        return cc % 2 == 0 ? cc : -1;
    }
}
